package dryven.persistence.provider.hibernate;

import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import com.mchange.v2.c3p0.DataSources;

import dryven.config.DatabaseConfiguration;
import dryven.config.DatabaseConfigurationSource;
import dryven.persistence.provider.JpaPersistenceProvider;

public abstract class C3P0PersistenceProvider extends JpaPersistenceProvider {

	private Map<DatabaseConfiguration, DataSource> _pooledDataSources = new HashMap<DatabaseConfiguration, DataSource>();
	
	public C3P0PersistenceProvider(DatabaseConfigurationSource dbCfgSource) {
		super(dbCfgSource);
	}

	protected DataSource createDataSource(DatabaseConfiguration cfg) {
		DataSource pooled = _pooledDataSources.get(cfg);
		if(pooled!=null) {
			return pooled;
		}
		try {
			Class.forName(cfg.getDriverClass());
			DataSource unpooled = DataSources.unpooledDataSource(cfg.getJDBCUrl(),cfg.getUsername(),cfg.getPassword());
			Map<String,Object> config = new HashMap<String, Object>();
			configurePool(config);
			pooled = DataSources.pooledDataSource(unpooled,config);
			_pooledDataSources.put(cfg, pooled);
			return pooled;
		} catch (SQLException e) {
			throw new RuntimeException(e);
		} catch (ClassNotFoundException e) {
			throw new RuntimeException(e);
		}
	}

	protected void unloadAllJDBCDrivers() {
		Enumeration<Driver> drivers = DriverManager.getDrivers();
		while(drivers.hasMoreElements()) {
			Driver d = drivers.nextElement();
			try {
				DriverManager.deregisterDriver(d);
			} catch (SQLException e) {}
		}
	}
	
	protected void configurePool(Map<String, Object> config) {
		config.put("maxPoolSize", 10);
		config.put("minPoolSize", 5);
		config.put("maxIdleTime", 1200);
		config.put("acquireIncrement", 3);
		config.put("initialPoolSize", 3);
	}

	@Override
	public void cleanup(DatabaseConfiguration config) {
		super.cleanup(config);
		DataSource pooledDs = _pooledDataSources.get(config);
		try {
			DataSources.destroy(pooledDs);
		} catch(Throwable e) {
			throw new RuntimeException(e);
		}
		unloadAllJDBCDrivers();
	}
}